package cn.bbstone.pisces2.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.twmacinta.util.MD5;

import cn.bbstone.pisces2.comm.BFileInfo;
import cn.bbstone.pisces2.comm.CS;
import cn.bbstone.pisces2.comm.Const;
import cn.bbstone.pisces2.comm.cache.ClientFliIndexCache;
import cn.bbstone.pisces2.comm.cache.ServerFliIndexCache;
import cn.bbstone.pisces2.comm.fli.FliIndex;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.netty.buffer.ByteBuf;

public class BFileUtil {
	private static Logger log = LoggerFactory.getLogger(BFileUtil.class);
	
    public static final String LF = "\n";

    private static int level = -1;

    public static boolean isBFileStream(ByteBuf msg) {
        int len = msg.readableBytes();
        log.debug("msg.len: {}", len);

        if (len < Const.bfile_info_prefix_len)
            return false;
        msg.markReaderIndex();
        byte[] data = new byte[Const.bfile_info_prefix_len];
        msg.readBytes(data);
        String prefix = BByteUtil.toStr(data);
        if (Const.bfile_info_prefix.equals(prefix)) {
            return true;
        }

        // stream not start with magic
        msg.resetReaderIndex();
        return false;
    }

    public static boolean isBFileStream(byte[] msg) {
        if (msg == null || msg.length < Const.magicLen)
            return false;
        byte[] data = new byte[Const.magicLen];
        System.arraycopy(msg, 0, data, 0, Const.magicLen);
        String magic = BByteUtil.toStr(data);
        if (Const.magic.equals(magic)) {
            return true;
        }
        return false;
    }


    public static String list(String filepath) {
        if (Files.notExists(Paths.get(filepath))) {
            log.warn("not found file/directory: {}", filepath);
        }
        StringBuilder sbu = new StringBuilder();
        File file = new File(filepath);
        if (Files.isDirectory(Paths.get(filepath))) {
            level = -1; // reset
            listAll(sbu, new File(filepath));
        } else {
            sbu.append(file.getName());
        }
        return sbu.toString();
    }

    private static void listAll(StringBuilder sbu, File file) {
        level++;
        File[] flist = file.listFiles();
        Arrays.sort(flist);
        for (File subfile : flist) {
            for (int i = 0; i < level; i++) {
                sbu.append("|   ");
            }
            sbu.append("|-- " + subfile.getName()).append(LF);
            if (subfile.isDirectory()) {
                listAll(sbu, subfile);
            }
        }
        level--;
    }


    public static List<BFileInfo> findServerFiles(String filepath) {
        return findFiles(filepath, getServerDir());
    }

    public static List<BFileInfo> findClientFiles(String filepath) {
        return findFiles(filepath, getClientDir());
    }


    /**
     * return all sub-files relative to server.dir
     *
     * @param filepath
     * @param basePath
     * @return
     */
    private static List<BFileInfo> findFiles(String filepath, String basePath) {
        if (Files.notExists(Paths.get(filepath))) {
            log.warn("not found file/directory: {}", filepath);
        }
        List<BFileInfo> fileList = new ArrayList<>();
        File file = new File(filepath);
        if (Files.isDirectory(Paths.get(filepath))) {
            findFile(fileList, file, basePath);
        } else {
            String relativePath = getRelativePath(file.getAbsolutePath(), basePath);
            BFileInfo fileInfo = new BFileInfo(relativePath, Const.BFILE_CAT_FILE, checksumFile(file), file.length());
            fileList.add(fileInfo);
        }
        return fileList;
    }

    private static void findFile(List<BFileInfo> fileList, File file, String basePath) {
        File[] flist = file.listFiles();
        Arrays.sort(flist);
        for (File subfile : flist) {
            String relativePath = getRelativePath(subfile.getAbsolutePath(), basePath);
            BFileInfo fileInfo = new BFileInfo(relativePath,
                    subfile.isDirectory() ? Const.BFILE_CAT_DIR : Const.BFILE_CAT_FILE,
                    // dir- md5(relativePath), file - md5(file:file_content)
                    subfile.isDirectory() ? checksumDir(relativePath) : checksumFile(subfile),
                    subfile.length());
            fileList.add(fileInfo);
            if (subfile.isDirectory()) {
                findFile(fileList, subfile, basePath);
            }
        }
    }
    // --------------------------

    /**
     * file is directory, calculate dir path string md5,
     * <p>
     * file is file, return file fingerprint
     *
     * @param file - dir/file, file should not be symbolic links, or it will throw exception FileNotFoundException
     * @return
     */
    public static String checksum(File file) {
//        long startTime = System.nanoTime();
        return file.isDirectory() ? CipherUtil.md5(file.getAbsolutePath()) : CipherUtil.md5(file);
//            return DigestUtils.md5DigestAsHex(new FileInputStream(filepath));
    }
    
    public static String checksumDir(String dir) {
    	if (StrUtil.isNotBlank(dir))
    		return CipherUtil.md5(dir);
    	return null;
    }
    public static String checksumFile(File file) {
    	if(file != null && file.isFile()) {
    		return CipherUtil.md5(file);
    	}
    	log.error("is not file, cannot calculate file checksum.");
    	return null;
    }
    
    /**
     * return the fileNo corresponding DIR/FILE checksum
     * 
     * @param fileNo - corresponding file can be DIR/FILE
     * @param cs - CS.SERVER/CS.CLIENT
     * @return
     */
    public static String checksum(long fileNo, CS cs) {
    	
    	// server dir/file checksum
    	if (CS.SERVER == cs) {
    		if (fileNo == 0) { // server fli.idx file
        		return CipherUtil.md5(new File(FLIUtil.getServerIndexPath()));
        	} else {
        		FliIndex fliIndex = getServerIndex(fileNo);
        		if (Const.BFILE_CAT_DIR.equals(fliIndex.getFileCat())) {
        			return CipherUtil.md5(fliIndex.getRpath());
        		} else if (Const.BFILE_CAT_FILE.equals(fliIndex.getFileCat())) {
        			String fullPath = getServerFullPath(fliIndex.getRpath());
        			return CipherUtil.md5(new File(fullPath));
        		} else {
        			log.error("[server] not support file type(D/F) checksum. fliIndex: {}", JSONUtil.toJsonStr(fliIndex));
        		}
        	}
    	} else if(CS.CLIENT == cs) {
    		if (fileNo == 0) { // client fli.idx file
        		return CipherUtil.md5(new File(FLIUtil.getClientIndexPath()));
        	} else {
        		FliIndex fliIndex = getClientIndex(fileNo);
        		if (Const.BFILE_CAT_DIR.equals(fliIndex.getFileCat())) {
        			return CipherUtil.md5(fliIndex.getRpath());
        		} else if (Const.BFILE_CAT_FILE.equals(fliIndex.getFileCat())) {
        			String clientFullPath = BFileUtil.getClientFullPathLocal(fliIndex.getRpath());
        			String tempFullPath = BFileUtil.getClientTempFileFullPath(clientFullPath);
        			return CipherUtil.md5(new File(tempFullPath));
        		} else {
        			log.error("[client] not support file type(D/F) checksum. fliIndex: {}", JSONUtil.toJsonStr(fliIndex));
        		}
        	}
    	}
    	return null;
    }

    /**
     * calculate string path file's fingerprint
     *
     * @param path
     * @return
     */
    public static String checksum(String path) {
        return checksum(new File(path));
    }


    /**
     * convert path which a server os path to client os path
     * e.g. server is *nix, client is windows,
     * need to convert server path format to client os platform format
     *
     * @param path
     * @return
     */
    public static String convertToLocalePath(String path) {
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            return path.replaceAll(Const.NIX_FILE_SEPARATOR, Matcher.quoteReplacement(File.separator));
        } else {
            return path.replaceAll(Const.WIN_FILE_SEPARATOR, File.separator);
        }
    }

    /**
     * @param serverFullPath
     * @return
     */
    public static String getServerRelativePath(String serverFullPath) {
        return getRelativePath(serverFullPath, getServerDir());
//        serverFullPath = getCanonicalPath(serverFullPath);
//        if (Files.notExists(Paths.get(serverFullPath)) || !serverFullPath.startsWith(getServerDir())) {
//            throw new RuntimeException(String.format("@param(filepath: %s) should be a exists server path and started with(%s).", serverFullPath, getServerDir()));
//        }
//        return getCanonicalRelativePath(serverFullPath.substring(getServerDir().length()));
    }

    public static String getClientRelativePath(String clientFullPath) {
        return getRelativePath(clientFullPath, getClientDir());
    }

    public static String getRelativePath(String fullPath, String basePath) {
        fullPath = getCanonicalPath(fullPath);
//        log.info("fullPath: {}, basePath: {}", fullPath, basePath);
        if (Files.notExists(Paths.get(fullPath)) || !fullPath.startsWith(basePath)) {
            throw new RuntimeException(String.format("@param(filepath: %s) should be an exists client path and started with(%s).", fullPath, basePath));
        }
        return getCanonicalRelativePath(fullPath.substring(basePath.length()));
    }

//    public static String getClientFullPath(String serverRelativePath) {
//        return getClientDir() + getCanonicalRelativePath(serverRelativePath);
//    }

    public static String getClientDir() {
        String clientdir = CtxUtil.getConfigModel().getClientRoot();
        if (StringUtils.isBlank(clientdir)) {
            throw new RuntimeException("client.dir property cannot be empty.");
        }
        return getCanonicalPath(clientdir);
    }

    public static String getServerDir() {
        String serverdir = CtxUtil.getConfigModel().getServerRoot();
        if (StringUtils.isBlank(serverdir)) {
            throw new RuntimeException("server.dir property cannot be empty.");
        }
        return getCanonicalPath(serverdir);
    }

    /**
     * if path not end with File.separator, append to it before return
     *
     * @param path
     * @return
     */
    private static String getCanonicalPath(String path) {
        path = convertToLocalePath(path);
        // append last File.separator for dir
        if (Files.isDirectory(Paths.get(path))) {
            path = (path.lastIndexOf(File.separator) == (path.length() - 1)) ? path : path + File.separator;
        }
        return path;
    }

    /**
     * remove the first File.separator
     *
     * @param path
     * @return
     */
    private static String getCanonicalRelativePath(String path) {
        path = convertToLocalePath(path);
        // remove the first File.separator
        if (path.startsWith(File.separator)) {
            path = path.substring(File.separator.length());
        }
        return path;
    }

    /**
     * delete file which relative to clientDir
     *
     * @param relativePath -
     * @return
     */
    public static void deleteRelClientPath(String relativePath) {
        String clientPathLocal = getClientFullPathLocal(relativePath);
        log.debug("----->clientPathLocal: {}", clientPathLocal);
        deleteFullPath(clientPathLocal);
    }

    public static void deleteFullPath(String fullPath) {
        if (Files.exists(Paths.get(fullPath))) {
            try {
                Files.delete(Paths.get(fullPath));
                log.debug("deleted file: {} ", fullPath);
            } catch (IOException e) {
                log.error(String.format("delete exist file(%s) error.", fullPath), e);
            }
        }
    }

    /**
     * @param relativePath      - server relative path(base on: server.dir)
     * @param createIfNotExists - check path or not
     * @return
     */
    public static String getClientFullPath(String relativePath, boolean createIfNotExists) {
        String clientFullPathLocal = getClientFullPathLocal(relativePath);
        if (createIfNotExists)
            createDirectories4Path(clientFullPathLocal);
        return clientFullPathLocal;
    }

    public static String getClientFullPathLocal(String relativePath) {
//        String relativePath = getCanonicalPath(filepath).substring(getServerDir().length());
        // only relativePath is FLI_IDX file store in client fli directory TODO support both idx & sp files
        String clientFullPath = FLIUtil.FLI_IDX.equals(relativePath) ? FLIUtil.getClientIndexPath()
                : (getClientDir() + getCanonicalRelativePath(relativePath));
//        String clipath = getClientDir() + getCanonicalRelativePath(relativePath);
        String clientFullPathLocal = convertToLocalePath(clientFullPath);
        return clientFullPathLocal;
    }

    public static String getServerFullPath(String relativePath) {
        String fullPath = getServerDir() + getCanonicalRelativePath(relativePath);
        String fullPathLocal = convertToLocalePath(fullPath);
        return fullPathLocal;
    }

    private static void createDirectories4Path(String clipath) {
        String dirpath = getCanonicalPath(clipath).substring(0, clipath.lastIndexOf(File.separator));
        if (Files.notExists(Paths.get(dirpath))) {
            mkdir(dirpath);
            log.debug("createDirectories for path: {}", clipath);
        }
//        if (Files.isDirectory(Paths.get(clipath))) {
//            dirpath = clipath;
//        } else {
////            dirpath = clipath.substring(0, clipath.lastIndexOf(System.getProperty("file.separator")));
//            dirpath = clipath.substring(0, clipath.lastIndexOf(File.separator));
//        }
    }

    /**
     * create directory
     *
     * @param dirpath -  a directory path
     */
    public static void mkdir(String dirpath) {
        if (Files.notExists(Paths.get(dirpath))) {
            try {
                Files.createDirectories(Paths.get(dirpath));
                log.debug(">>>>>>>>>>>>>> created dir: {}", dirpath);
            } catch (IOException e) {
                log.error("dir create fail. ", e);
            }
        }
    }

    /**
     * @param clientFullPath - client full path
     * @return
     */
    public static String getClientTempFileFullPath(String clientFullPath) {
        if (isDir(clientFullPath)) return clientFullPath;
        return clientFullPath + CtxUtil.getConfigModel().getPostfix();
    }

    /**
     * @param serverRelativeFile
     * @return
     */
    public static String getPartFileFromRelative(String serverRelativeFile) {
        String clientFullPath = BFileUtil.getClientFullPath(serverRelativeFile, false);
        String tempFile = BFileUtil.getClientTempFileFullPath(clientFullPath);
        return tempFile;
    }

    /**
     * @param serverFileFullPath
     * @return
     */
    public static String getPartFileFromFull(String serverFileFullPath) {
        String serverRelativeFile = getServerRelativePath(serverFileFullPath);
        String clientFullPath = BFileUtil.getClientFullPath(serverRelativeFile, false);
        String tempFile = BFileUtil.getClientTempFileFullPath(clientFullPath);
        return tempFile;
    }


    public static boolean isDir(String filepath) {
        return Files.isDirectory(Paths.get(filepath));
    }

    /**
     * rename temp file to client file
     *
     * @param tmpFile
     * @param clipath
     */
    public static boolean renameCliTempFile(File tmpFile, String clipath) {
    	/**
         * Renames the file denoted by this abstract pathname.
         *
         * <p> Many aspects of the behavior of this method are inherently
         * platform-dependent: The rename operation might not be able to move a
         * file from one filesystem to another, it might not be atomic, and it
         * might not succeed if a file with the destination abstract pathname
         * already exists.  The return value should always be checked to make sure
         * that the rename operation was successful.
         *
         * <p> Note that the {@link java.nio.file.Files} class defines the {@link
         * java.nio.file.Files#move move} method to move or rename a file in a
         * platform independent manner.
         */
//    	tmpFile.renameTo(new File(clipath));
    	try {
			Files.move(tmpFile.toPath(), new File(clipath).toPath());
			return true;
		} catch (IOException e) {
			log.error("rename file error.", e);
		}
    	return false;
    }

    /**
     * build FileRsp
     *
     * @param serverpath
     * @param filesize
     * @param checksum
     * @param reqTs
     * @return
     */
//    public static ByteBuf buildRspFile(String serverpath, long filesize, String checksum, long reqTs) {
//        return buildRsp(BFileCmd.RSP_FILE, serverpath, filesize, checksum, null, null, reqTs);
//    }
//
//    public static ByteBuf buildRspDir(String serverpath, long reqTs) {
//        return buildRsp(BFileCmd.RSP_DIR, serverpath, 0, ConstUtil.EMPTY_STR, null, null, reqTs);
//    }

    /**
     * @param rpath   - rpath(relative path)
     * @param rspData -
     * @param reqTs
     * @return
     */
//    public static BFileMsg.BFileRsp buildRspList2(String rpath, String rspData, long reqTs) {
//        // checksum: rspData 's md5 hash
//        String checksum = MD5.asHex(BByteUtil.toBytes(rspData));
////        return buildRsp(BFileCmd.RSP_LIST, serverpath, 0, checksum, rspData, null, reqTs);
//        BFileMsg.BFileRsp rsp = BFileMsg.BFileRsp.newBuilder()
//                .setId(getReqId(rpath)) // rspId = reqId
//                .setCmd(BFileCmd.RSP_LIST) //BFileCmd.CMD_RSP)
//                .setFilepath(rpath) // relative path(not contains client.dir or server.dir)
//                .setFileSize(0) // should be file-list index filesize
//                .setChecksum(checksum) // file fingerprint/ md5(server_dir_abs_path)
//                .setRspData(StringUtils.trimToEmpty(rspData))
//                .setChunkData(ByteString.EMPTY)
//                .setReqTs(reqTs)
//                .setRspTs(System.currentTimeMillis())
//                .build();
//        return rsp;
//    }

    /**
     * build ListRsp
     *
     * @param serverpath
     * @param rspData
     * @param reqTs
     * @return
     */
//    public static ByteBuf buildRspList(String serverpath, String rspData, long reqTs) {
//        // checksum: rspData 's md5 hash
//        String checksum = MD5.asHex(BByteUtil.toBytes(rspData));
//        return buildRsp(BFileCmd.RSP_LIST, serverpath, 0, checksum, rspData, null, reqTs);
//    }


    /**
     * @param filepath - file path relative server.dir
     */
    public static String getReqId(String filepath) {
        return MD5.asHex(BByteUtil.toBytes(filepath));
    }

//    private static FliIndex getIndex(long fileNo, String cacheFlag) {
//        if (fileNo == 0) {
//            return FliIndex.builder()
//                    .fileCat(Const.BFILE_CAT_FILE)
//                    .rpath(FLIUtil.FLI_IDX)
//                    .build();
//        }
//        if (Const.SERVER.equals(cacheFlag)) {
//            return ServerFliIndexCache.getServerIndex(fileNo);
//        }
//        if (Const.CLIENT.equals(cacheFlag)) {
//            return ClientFliIndexCache.getClientIndex(fileNo);
//        }
//        return null;
//    }

    public static FliIndex getServerIndex(long fileNo) {
        return ServerFliIndexCache.getServerIndex(fileNo);
//        return getIndex(fileNo, Const.SERVER);
    }

    /**
     * get client index and not update client fli index cache pos
     * @param fileNo
     * @return
     */
    public static FliIndex getClientIndex(long fileNo) {
        return ClientFliIndexCache.getClientIndexNotUpdatePos(fileNo);
    }

//    public static String getRpath(long fileNo) {
//        FliIndex fliIndex = getClientIndex(fileNo);
//        if (fliIndex == null) return null;
//        return fliIndex.getRpath();
//    }

    public static File newFile(long fileNo) {
        FliIndex fliIndex = getServerIndex(fileNo);
        if (Const.BFILE_CAT_DIR.equals(fliIndex.getFileCat())) {
            log.warn("fileNo: {} is directory, will not send file info.", fileNo);
            return null;
        }
        String rpath = fliIndex.getRpath();
        String fullPath = getServerFullPath(rpath);
//        if (fileNo == 5003) {
//            log.debug("rpath: {}, fullPath: {}", rpath, fullPath);
//        }
//        if (fileNo == 700) { // line700: 700:F:/00a1-goal/lab101/ImSys/WebRTC : Jitsi : 多人视频通讯常用架构 Mesh : MCU : SFU.docx
//            log.info("rpath: {}, fullPath: {}", rpath, fullPath);
//        }
        return new File(fullPath);
    }

    public static byte[] file2Bytes(File file) {
        try {
            FileInputStream fis = new FileInputStream(file);
            byte[] fileBytes = new byte[(int) file.length()];
            fis.read(fileBytes);
            fis.close();
            return fileBytes;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * escape path special character
     * <p>
     *  TODO find a way to keep special character in cross-platform, never change any file info after transfer
     *
     * @param rpath - path with special character "[:*?|<>]"
     * @return - path with special character "[:*?|<>]" replaced by "_"
     */
    public static String escapePath(String rpath) {
        if (StrUtil.isBlank(rpath)) return null;
        String trimRPath = trimRPath(rpath);
        return trimRPath.replaceAll(Const.PATH_SPECIAL_CHAR, Const.PATH_SPECIAL_CHAR_REPLACER);
    }

    /**
     * J:\assets\assets_pro\xxx\wos-workdocs \000.项目管理\X重构一期里程碑.xlsx
     * rpath: \assets_pro\xxx\wos-workdocs \000.项目管理\X重构一期里程碑.xlsx
     * rpathDir: \assets_pro\xxx\wos-workdocs \
     * rpathFile: 000.项目管理\WOS重构一期里程碑.xlsx
     *
     *  TODO server generated fli.idx form out the rpath file.separator, to handle this case if server is not *nix os
     *
     * @param rpath
     * @return
     */
    public static String trimRPath(String rpath) {
        List<String> rpathToken = StrUtil.splitTrim(rpath, Const.NIX_FILE_SEPARATOR_RPATH);
        return StrUtil.join(Const.NIX_FILE_SEPARATOR_RPATH, rpathToken);
    }

    /**
     * BUGFIX: file2Bytes asHex will cause OOM
     * should never output file's bytes asHex when file too large(about 600M) will cause OOM
     *
     * @param file
     * @return
     */
    public static String file2BytesHex(File file) {
//        return CipherUtil.md5(file);
        return MD5.asHex(file2Bytes(file));
    }


    public static void main(String[] args) throws MalformedURLException {
//        int[] arr = {1, 2, 3, 4, 5};
//        int[] arr2 = {5, 6, 7, 8, 9};
//        System.arraycopy(arr, 1, arr2, 0, 3);
//        System.out.println(Convert.toStr(arr2));
//        System.arraycopy(arr, 0, arr2, 3, 1);
//        System.out.println(Convert.toStr(arr2));
//
//        // 64 bytes
//        byte[] origin = "hello, this is a test content of byte in system.arraycopy method".getBytes(StandardCharsets.UTF_8);
//        log.info("orgin.len: {}", origin.length);
//
//        byte[] b1 = new byte[33];
//        byte[] b2 = new byte[31];
//        System.arraycopy(origin, 0, b1, 0, 33);
//        System.arraycopy(origin, 33, b2, 0, 31);
//
//        byte[] b3 = new byte[origin.length];
//        System.arraycopy(b1, 0, b3, 0, 33);
//        System.arraycopy(b2, 0, b3, 33, 31);
//        String b3Str = new String(b3, StandardCharsets.UTF_8);
//        log.info("b3str: {}", b3Str);

//        ServerFliIndexCache.init(Const.SERVER);
//        File file = newFile(946);
//        log.info("file946: {}", file.getName());

//        String path = "/Users/bbstone/workdir/assets/assets_docs/00a1-goal/lab101/IaaS和PaaS技术选型/RefDoc/中立观点：无服务器架<构的特>点 | Thought < > : Works.docx";
//        String path = "20200608ERROR 604 (42P00)- Syntax error. Mismatched input. Expecting \"CONSTRAINT\", got \"LAST\" at line 1, column 135. (state=42P00,code=604)";
//        String urlPath = escapePath(path);
//        log.info("urlPath: {}", urlPath);
//        String rpath = "J:\\assets\\assets_pro\\xxx\\wos-workdocs \\000.项目管理\\X重构一期里程碑.xlsx";
//        String rpath = "J:/assets/assets_pro/xxx/wos-workdocs /000.项目管理/|X重构一期里程碑.xlsx";
//        String trimRPath = escapePath(rpath);
//        log.info("trimRPath: {}", trimRPath);

//        setBufferSize("8m");
//        log.info("SBUF_SIZE: {}", SBUF_SIZE);
        
//        String rpath = "/Users/bbstone/test_client/Pi2-1.0.0-20220927-win32.win32.x86_64.zip";
//        BFileUtil.renameCliTempFile(new File("/Users/bbstone/test_client/Pi2-1.0.0-20220927-win32.win32.x86_64.zip.temp"), rpath);
        
        
        String rpath = "/Users/bbstone/test_client/readme.txt";
        BFileUtil.renameCliTempFile(new File("/Users/bbstone/test_client/readme.txt.temp"), rpath);
    }


}
